#include <stdio.h>
#include <string.h>
#include "crypto/sm3.h"

// Helper function to convert hex char to int
int hex_char_to_int(char c)
{
    if (c >= '0' && c <= '9')
        return c - '0';
    if (c >= 'a' && c <= 'f')
        return c - 'a' + 10;
    if (c >= 'A' && c <= 'F')
        return c - 'A' + 10;
    return -1;
}

// Helper function to convert hex string to byte array
void hex_string_to_bytes(const char *hex_str, unsigned char *byte_array, size_t byte_array_len)
{
    size_t hex_len = strlen(hex_str);
    for (size_t i = 0; i < byte_array_len && (i * 2 + 1) < hex_len; i++)
    {
        byte_array[i] = (hex_char_to_int(hex_str[i * 2]) << 4) + hex_char_to_int(hex_str[i * 2 + 1]);
    }
}

// 打印十六进制值
void print_hex(const char *label, const unsigned char *data, size_t len)
{
    printf("%s: ", label);
    for (size_t i = 0; i < len; i++)
    {
        printf("%02x", data[i]);
    }
    printf("\n");
}

// 测试SM3哈希函数
// Returns number of failed assertions in this test function
int test_sm3_hash()
{
    unsigned char digest[32];
    int failures = 0;

    printf("\n--- 测试 SM3 哈希算法 ---\n");

    // Known SM3 hash for empty string: 1ab21d8355cfa17f8e61194831e81a8f22bec8c728f3b7446424895371577357
    const char *empty_str_hex = "1ab21d8355cfa17f8e61194831e81a8f22bec8c728f3b7446424895371577357";
    unsigned char expected_empty_digest[32];
    hex_string_to_bytes(empty_str_hex, expected_empty_digest, 32);

    // Known SM3 hash for "abc": 66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0
    const char *abc_str_hex = "66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0";
    unsigned char expected_abc_digest[32];
    hex_string_to_bytes(abc_str_hex, expected_abc_digest, 32);

    // 1. 测试空消息
    const char *input1 = "";
    printf("输入: \"%s\" (空字符串)\n", input1);
    sm3_hash((const unsigned char *)input1, strlen(input1), digest);
    print_hex("计算哈希", digest, 32);
    print_hex("期望哈希", expected_empty_digest, 32);
    if (memcmp(digest, expected_empty_digest, 32) == 0)
    {
        printf("结果: 通过\n");
    }
    else
    {
        printf("结果: 失败 - 哈希值不匹配!\n");
        failures++;
    }
    printf("\n");

    // 2. 测试字符串 "abc"
    const char *input2 = "abc";
    printf("输入: \"%s\"\n", input2);
    sm3_hash((const unsigned char *)input2, strlen(input2), digest);
    print_hex("计算哈希", digest, 32);
    print_hex("期望哈希", expected_abc_digest, 32);
    if (memcmp(digest, expected_abc_digest, 32) == 0)
    {
        printf("结果: 通过\n");
    }
    else
    {
        printf("结果: 失败 - 哈希值不匹配!\n");
        failures++;
    }
    printf("\n");

    // 3. 测试长消息 (1024 'a's)
    //    Note: We don't have a pre-calculated hash for this one in this script,
    //    so this part will primarily be a "visual" check or a check that it runs without error.
    //    For a real test suite, this should also have a known hash.
    char long_message[1024];
    memset(long_message, 'a', sizeof(long_message));
    printf("输入: 1024个 'a' 字符\n");
    sm3_hash((const unsigned char *)long_message, sizeof(long_message), digest);
    print_hex("计算哈希 (1024个'a')", digest, 32);
    printf("结果: (目视检查或确保无运行时错误)\n"); // No assertion for this specific long message without a known hash
    printf("--- SM3 哈希算法测试完成 ---\n");
    return failures;
}

// 测试带盐值的密码哈希
// Returns number of failed assertions in this test function
int test_password_hash()
{
    unsigned char salt[16] = {
        0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
        0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10};
    unsigned char hash[32];
    const char *password = "password123";
    int failures = 0;

    printf("\n--- 测试带盐值的密码哈希 ---\n");

    printf("密码: \"%s\"\n", password);
    print_hex("使用盐值", salt, 16);

    // 哈希密码
    hash_password(password, salt, hash);
    print_hex("计算的密码哈希", hash, 32);
    printf("\n");

    // 验证正确密码
    printf("验证正确密码 (\"%s\"):\n", password);
    int result_correct = verify_password(password, salt, hash);
    printf("验证 API 返回值: %d\n", result_correct);
    if (result_correct)
    {
        printf("结果: 通过\n");
    }
    else
    {
        printf("结果: 失败 - 正确密码未能通过验证!\n");
        failures++;
    }
    printf("\n");

    // 验证错误密码
    const char *wrong_password = "wrongpassword";
    printf("验证错误密码 (\"%s\"):\n", wrong_password);
    int result_wrong = verify_password(wrong_password, salt, hash);
    printf("验证 API 返回值: %d\n", result_wrong);
    if (!result_wrong)
    {
        printf("结果: 通过 (错误密码被正确拒绝)\n");
    }
    else
    {
        printf("结果: 失败 - 错误密码通过了验证!\n");
        failures++;
    }
    printf("--- 带盐值的密码哈希测试完成 ---\n");
    return failures;
}

// 测试随机盐值生成
// Returns number of failed assertions in this test function
int test_salt_generation()
{
    unsigned char salt1[16];
    unsigned char salt2[16];
    int failures = 0;

    printf("\n--- 测试随机盐值生成 ---\n");

    // 生成两个随机盐值
    printf("生成盐值 1...\n");
    generate_salt(salt1);
    print_hex("盐值 1", salt1, 16);
    printf("\n");

    printf("生成盐值 2...\n");
    generate_salt(salt2);
    print_hex("盐值 2", salt2, 16);
    printf("\n");

    // 比较两个盐值是否相同
    printf("比较盐值 1 和盐值 2:\n");
    if (memcmp(salt1, salt2, 16) != 0)
    {
        printf("结果: 通过 (盐值不同，符合预期)\n");
    }
    else
    {
        // This has a very small chance of happening naturally (1 in 2^128).
        // If it happens frequently, there's an issue with generate_salt.
        printf("结果: 注意 - 两个随机盐值相同 (极小概率事件，若频繁发生则表明存在问题)\n");
        // Not strictly a failure unless it's reproducible and indicates non-randomness.
        // For this test, we'll consider it a pass but with a warning.
        // To make it a failure, uncomment: failures++;
    }
    printf("--- 随机盐值生成测试完成 ---\n");
    return failures;
}

int main()
{
    int total_failures = 0;

    printf("SM3 功能测试套件\n");
    printf("===========================\n");

    total_failures += test_sm3_hash();
    total_failures += test_password_hash();
    total_failures += test_salt_generation();

    printf("\n\n--- 测试总结 ---\n");
    if (total_failures == 0)
    {
        printf("所有测试通过!\n");
    }
    else
    {
        printf("%d 个测试断言失败.\n", total_failures);
    }
    printf("===========================\n");

    return total_failures == 0 ? 0 : 1; // Return 0 on success, 1 on failure for CTest
}